<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.5.0 / SVN信息: $Id: class.JCAT_ASSERT.php 1603 2009-03-31 15:35:42Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/
namespace JCAT ;


/**
 * 断言函数 集合
 * 为整个项目提供断言
 *
 * @author		alee
 * @access		public
 * @last		2007.12.6
 */
class ASSERT
{
	/**
	 * 断言
	 * php的 原生函数 assert() 仅仅给出一个警告
	 * 本函数在 $Expression 不满足时 抛出一个 ASSERTException 异常，使你无法忽视错误，并且可以通过 JCAT::SetProjectState 关闭JCAT提供的断言函数
	 * 
	 * @access	public
	 * @param	$Expression		 bool	表达式，当该表达式的结果为 false,null,0 或 空 时，断言函数 抛出异常 
	 * @param	$sDescription=null string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_(  $Expression, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) or $Expression)
		{
			return ;
		}
		
		if(empty($sDescription))
		{
			$sDescription = '一个断言失败触发了 ASSERTException 异常！该代码的作者没有为此断言留下描述性文字，JCAT 建议所有的断言都应该有一段意简言赅的描述。' ;
		}

		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,1)) ;
	}



	/**
	 * 整数断言，传入的变量必须为整数类型
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的变量
	 * @param	$sDescription=null	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_INT( $Variable, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( is_int($Variable) )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = 'ASSERT_INT 断言失败触发了 ASSERTException 异常。请确保保传入的 $Variable 是一个整数类型的变量。' ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,2)) ;
	}

	/**
	 * 数字断言，传入的变量必须为一个数字（整数 和 浮点）
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的变量
	 * @param	$sDescription=null	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_NUM( $Variable, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( is_numeric($Variable) )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = 'ASSERT_NUM 断言失败触发了 ASSERTException 异常。请确保传入的 $Variable 是一个数字（包括整数和浮点）。' ;
		}
		
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,3)) ;
	}



	/**
	 * 字符串断言，传入的变量必须为字符串类型
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的变量
	 * @param	$sDescription=null	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_STRING( $Variable, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( is_string($Variable) )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = 'ASSERT_STRING 断言失败触发了 ASSERTException 异常。请确保传入的 $Variable 是一个字符串类型的变量。' ;
		}
		
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,4)) ;
	}



	/**
	 * 布尔类型断言，传入的变量必须为布尔类型
	 * 此断言 不会检查 变量值的真或假，仅仅检查变量的类型是否为布尔类型
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的变量
	 * @param	$sDescription=null	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_BOOL( $Variable, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( is_bool($Variable) )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = 'ASSERT_BOOL 断言失败触发了 ASSERTException 异常。请确保传入的 $Variable 是一个布尔类型的变量。' ;
		}
		
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,5)) ;
	}


	/**
	 * 对象实例断言，传入的变量必须为对象
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的变量
	 * @param	$sClass=''		string	对象类型, null 或 '' 则表示不限，只要是对象即可。此断言对类的检查是不严格的，满足IsKindOf() 即可
	 * @param	$sDescription=''	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_INSTANCE(  $Variable, $sClass='', $sDescription='' ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( is_object($Variable) )
		{
			// 任意 类型 实例
			if( $sClass==='' )
			{
				return ;
			}
			
			// 指定 类
			else if( class_exists($sClass) and GlobalFunc::IsKindOf($Variable,$sClass) )
			{
				return ;
			}
			
			// 指定 接口
			else if( interface_exists($sClass) and GlobalFunc::HasImplementedTo($Variable,$sClass) )
			{
				return ;
			}
		}

		if( empty($sDescription) )
		{
			$sDescription = 'ASSERT_INSTANCE 断言失败触发了 ASSERTException 异常。请确保传入的 $Variable 是一个'.($sClass?"{$sClass}类型的":'').'对象。' ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,6)) ;
	}


	/**
	 * 数组断言，传入的变量必须为数组类型
	 * 
	 * @access	public
	 * @param	$Variable				mixed	传入检查的变量
	 * @param	$arrElementType=null	array	数组各元素的类型,null 或 '' 则表示不限。$sElementType可以是： string,int,float,bool,array,object 等基础类型，或是 一个类名。 此断言对类的检查是不严格的，满足IsKindOf() 即可
	 * @param	$sDescription=null		string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_ARRAY( $Variable, $ElementTypes=null, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
				
		if( is_array($Variable) )
		{			
			// 对数组成员的类型进一步检查
			if( $ElementTypes===null )
			{
				return ;
			}
				
			if( !is_array($ElementTypes) )
			{
				$ElementTypes = (array) $ElementTypes ;
			}
			
			if( GlobalFunc::CheckArray($Variable,$ElementTypes) )
			{
				return ;
			}
		}
		
		if( empty($sDescription) )
		{
			$sDescription = 'ASSERT_ARRAY 断言失败触发了 ASSERTException 异常。请确保传入的 $Variable 是一个数组类型的变量'.($ElementTypes?"并且该数组内的所有元素均为“{$ElementTypes}”类型":'').'。' ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,7)) ;
	}





	/**
	 * 空断言，传入的变量必须为null
	 * 此断言严格检查传入变量是否为null，  即使 0 和 '' 也会遭至断言失败。
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的变量
	 * @param	$sDescription=null	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_NULL( $Variable, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( $Variable===null )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = 'ASSERT_NULL 断言失败触发了 ASSERTException 异常。请确保传入的 $Variable 此时必须为null。' ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,8)) ;
	}



	/**
	 * 非空断言，传入的变量不能为null。
	 * 此断言仅仅严格检查传入变量是否为null，  0 和 '' 不会遭至断言失败。
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的变量
	 * @param	$sDescription=null	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_NOTNULL( $Variable, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( $Variable!==null )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = 'ASSERT_NULL 断言失败触发了 ASSERTException 异常。请确保传入的 $Variable 不能为null。' ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,9)) ;
	}



	/**
	 * 路径断言，检查传入变量所代表的路径是否有效。
	 * 此断言 不对文件或目录作出判断。
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的路径
	 * @param	$sDescription=null	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_PATH( $Variable, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( file_exists($Variable) )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = "ASSERT_PATH 断言失败触发了 ASSERTException 异常。请确保路径{$Variable} 有效。" ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,10)) ;
	}



	/**
	 * 文件断言，检查传入变量所代表的文件是否有效。
	 * 此断言不但要求路径正确有效，同时还必须是一个文件。
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的路径
	 * @param	$sDescription=null	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_FILE( $Variable, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( is_file($Variable) )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = "ASSERT_FILE 断言失败触发了 ASSERTException 异常。请确保路径{$Variable} 存在，并且是一个文件（而不是目录）。" ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,11)) ;
	}



	/**
	 * 目录断言，检查传入变量所代表的目录是否有效。
	 * 此断言不但要求路径正确有效，同时还必须是一个目录。
	 * 
	 * @access	public
	 * @param	$Variable			mixed	传入检查的路径
	 * @param	$sDescription=null	string	当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_DIR( $Variable, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( is_dir($Variable) )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = "ASSERT_DIR 断言失败触发了 ASSERTException 异常。请确保路径{$Variable} 存在，并且是一个目录（而不是文件）。" ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,12)) ;
	}
	
	
	/**
	 * 继承断言，检查传入的类或对象是否继承自某个类
	 * 
	 * @access	public
	 * @param	$SubClassNameOrObject	string,object	子类名或对象变量
	 * @param	$sParentClass			string			父类名
	 * @param	$sDescription=null		string			当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_INHERIT( $SubClassNameOrObject,  $sParentClass, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( GlobalFunc::IsKindOf($SubClassNameOrObject,$sParentClass) )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = "ASSERT_INHERIT 断言失败触发了 ASSERTException 异常。请确保 \$SubClassNameOrObject 继承自 {$sParentClass} 。" ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,13)) ;
	}



	/**
	 * 接口断言，检查传入的对象或类 是否实现 一个接口
	 * 
	 * @access	public
	 * @param	$ClassNameOrObject	string,object	类名或对象变量
	 * @param	$sInterfaceName		string			接口名
	 * @param	$bStrictly=true		bool			是否严格检查
	 * @param	$sDescription=null	string			当断言异常被触发时，描述该断言的消息
	 * @return	void
	 */
	static public function ASSERT_IMPLEMENTS( $SubClassNameOrObject,  $sInterfaceName,  $bStrictly=true, $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}
		
		if( GlobalFunc::HasImplementedTo($SubClassNameOrObject,$sInterfaceName,$bStrictly) )
		{
			return ;
		}
		
		if( empty($sDescription) )
		{
			$sDescription = "ASSERT_IMPLEMENTS 断言失败触发了 ASSERTException 异常。请确保 \$SubClassNameOrObject({$SubClassNameOrObject}) 实现了接口 {$sInterfaceName} 。" ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,14)) ;
	}
	
	
	/**
	 * 检查 变量类型，传入的变量 必须至少符合随后给出的类型中的一个
	 * 
	 * @access	public
	 * @param	$Variable	mixed			待检查的变量名
	 * @param	$Types		array,string	类型
	 * @static
	 * @return	void
	 */
	static public function ASSERT_ISTHESE( $Varialbe, $Types,  $sDescription=null ) 
	{
		if( !ProjectState::Get(ProjectState::ASSERT) )
		{
			return ;
		}

		if( call_user_func_array(array('JCAT\GlobalFunc','IsThese'),array($Varialbe,$Types)) )
		{
			return ;
		}

		if( empty($sDescription) )
		{
			$sTypes = implode(', ',$Types) ;
			$sDescription = "ASSERT_ISTHESE 断言失败触发了 ASSERTException 异常。请确保变量  \$Varialbe 为以下类型：{$sTypes} 。" ;
		}
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,14)) ;
	}
	
	
	/**
	 * 检查 变量类型，传入的变量 必须至少符合随后给出的类型中的一个
	 * 
	 * @access	public
	 * @param	$sClassName							string					待检查的类名
	 * @param	$BaseClassOrInterfaces=array()		array:string,string		基类或接口
	 * @static
	 * @return	void
	 */
	static public function ASSERT_ISCLASS($sClassName,$BaseClassOrInterfaces=array(),$sDescription=null)
	{
		ASSERT::ASSERT_STRING($sClassName) ;
		ASSERT::ASSERT_ISTHESE($BaseClassOrInterfaces,array('array:string','string','null'));

		// 检查类是否存在
		if( !class_exists($sClassName) )
		{
			if( empty($sDescription) )
			{
				$sDescription = "ASSERT_ISCLASS 断言失败触发了 ASSERTException 异常。参数 \$sClassName({$sClassName}) 不是一个已定义的类。" ;
			}

			throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,__macro_exception_code__)) ;
		}
		
		// 检查基类 和 接口
		if( $BaseClassOrInterfaces!==null )
		{
			if( is_string($BaseClassOrInterfaces) )
			{
				$arrBaseClassOrInterfaces = array($BaseClassOrInterfaces) ;
			}
			else
			{
				$arrBaseClassOrInterfaces = $BaseClassOrInterfaces ;
			}
			
			foreach ($arrBaseClassOrInterfaces as $sClass)
			{
				$bIsInterface = false ;
					
				if( Package::ClassExists($sClass)
						or ($bIsInterface=Package::ClassExists($sClass,true)) )
				{
					if( !GlobalFunc::IsKindOf($sClassName,$sClass) )
					{
						if( empty($sDescription) )
						{
							$sDescription = 'ASSERT_ISCLASS 断言失败触发了 ASSERTException 异常。' . 
									( $bIsInterface ?
											"“{$sClassName}”必须实现接口“{$sClass}”。" :
											"“{$sClassName}”必须是“{$sClass}”的派生类。"
									) ;
						}

						throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,__macro_exception_code__)) ;
					}
				}
				
				// 错误的 输入
				else 
				{
					if( empty($sDescription) )
					{
						$sDescription = "ASSERT_ISCLASS 断言失败触发了 ASSERTException 异常。“{$sClass}”的既不是已定义的类，也不是接口。" ;
					}
		
					throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,__macro_exception_code__)) ;
				}
			}
		}
	}

	/**
	 * 检查变量值，传入的变量 必须至少符合随后给出的值中的一个
	 * 
	 * @access	public
	 * @param	$Variable	mixed	待检查的变量名
	 * @param	$sFirstType	string	第一项类型
	 * @static
	 * @return	void
	 */
	static public function ASSERT_INVALUE( $Varialbe, array $arrValues,  $sDescription=null ) 
	{
		if($sDescription===NULL)
		{
			$sDescription = Language::SentenceEx('参数值(%s)非法。','JCAT',null,strval($Varialbe)) ;
		}
		
		// 检查类型
		ASSERT_ISTHESE($Varialbe,array('string','int','bool'),$sDescription) ;
		
		// 
		foreach ($arrValues as $Value)
		{
			if( $Varialbe===$Value )
			{
				return ;
			}
		}
		
		throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,Exception::MakeExceptionCode(__CLASS__,15))) ;
	}
	

	/**
	 * 检查变量值，传入变量的值必须为数字类型，且在随后给出的范围内
	 * 
	 * @access	public
	 * @param	$Variable	mixed		待检查的变量名
	 * @param	$Min		int,float	范围的左端
	 * @param	$Max		int,float	范围的右端
	 * @static
	 * @return	void
	 */
	static public function ASSERT_INRANGE( $Varialbe, $Min, $Max,  $sDescription=null ) 
	{
		if($sDescription===NULL)
		{
			$sDescription = Language::SentenceEx('参数值(%s)非法。','JCAT',null,strval($Varialbe)) ;
		}
		
		// 检查类型
		self::ASSERT_ISTHESE($Varialbe,array('bool','float'),$sDescription) ;
		
		// 
		if( $Varialbe<$Min or $Varialbe>$Max )
		{
			throw new ASSERTException($sDescription,Exception::MakeExceptionCode(__CLASS__,Exception::MakeExceptionCode(__CLASS__,__macro_exception_code__))) ;
		}
	}
	
}

/**
 * 断言异常类，当断言失败是，抛出此异常
 *
 * @author		alee
 * @access		public
 * @last		2007.12.6
 */
class ASSERTException extends Exception
{
/* 可显示 断言处的代码*/
}


/*macro_exception_code:15*/
?>